/*
 * fat-utils.h
 *
 *  Created on: 14/09/2011
 *      Author: fabian
 */

#ifndef FAT_UTILS_H_
#define FAT_UTILS_H_
#include <stdlib.h>
#include <sys/types.h>
#include <sys/types.h>
#include <string.h>
#include <resolv.h>
#include <pthread.h>
#include <fcntl.h>
#include <netdb.h>
#include <wchar.h>
#include <unistd.h>

// Tamaño de sector.
#define SECTOR_SIZE 512

/* FAT32 valores y macros */
#define	 FAT32_EOC_VALUE	0x0FFFFFF8	//it was 0x0FFFFFFF but linux driver set
#define  FAT32_BAD_VALUE	0x0FFFFFF7

#define  FAT32_ISEOC(EntryValue)  (((EntryValue) & 0x0FFFFFFF) >= 0x0FFFFFF8)
#define  FAT32_ISFREE(EntryValue) (((EntryValue) & 0x0FFFFFFF) == 0x00000000)
#define  FAT32_ISBAD(EntryValue)  (EntryValue == 0x0FFFFFF7)
#define  FAT32_LEGALCLUS(EntryValue)  (!( (FAT32_ISEOC(EntryValue)) || (FAT32_ISFREE(EntryValue)) || (FAT32_ISBAD(EntryValue))))

// Directory valores y macros
#define FREEENT  0xE5 /* The directory entry is free             */
#define ENDOFDIR 0x00 /* This and the following entries are free */

#define DIRENT_ISFREE(D) \
	(((D) == FREEENT) || ((D) == ENDOFDIR))

#define DIRENT_ISLAST(D) \
	(D == ENDOFDIR)

typedef struct {
	uint8_t BS_jmpBoot[3];
	uint8_t BS_OEMName[8];
	uint16_t BPB_BytsPerSec;
	uint8_t BPB_SecPerClus;
	uint16_t BPB_ResvdSecCnt;
	uint8_t BPB_NumFATs;
	uint16_t BPB_RootEntCnt;
	uint16_t BPB_TotSec16;
	uint8_t BPB_Media;
	uint16_t BPB_FATSz16;
	uint16_t BPB_SecPerTrk;
	uint16_t BPB_NumHeads;
	uint32_t BPB_HiddSec;
	uint32_t BPB_TotSec32;
	uint32_t BPB_FATSz32;
	uint16_t BPB_ExtFlags;
	uint16_t BPB_FSVer;
	uint32_t BPB_RootClus;
	uint16_t BPB_FSInfo;
	uint16_t BPB_BkBootSec;
	uint8_t BPB_Reserved[12];
	uint8_t BS_DrvNum;
	uint8_t BS_Reserved1;
	uint8_t BS_BootSig;
	uint32_t BS_VolID;
	uint8_t BS_VolLab[11];
	uint8_t BS_FilSysType[8];
}__attribute__ ((packed)) BPB;

typedef struct {
	uint32_t FSI_LeadSig;
	uint8_t FSI_Reserved1[480];
	uint32_t FSI_StrucSig;
	uint32_t FSI_Free_Count;
	uint32_t FSI_Nxt_Free;
	uint8_t FSI_Reserved2[12];
	uint32_t FSI_TrailSig;
}__attribute__ ((packed)) FSInfo;

typedef struct {
	uint8_t DIR_Name[11];
	uint8_t DIR_Attr;
	uint8_t DIR_NTRes;
	uint8_t DIR_CrtTimeTenth;
	uint16_t DIR_CrtTime;
	uint16_t DIR_CrtDate;
	uint16_t DIR_LstAccDate;
	uint16_t DIR_FstClusHI;
	uint16_t DIR_WrtTime;
	uint16_t DIR_WrtDate;
	uint16_t DIR_FstClusLO;
	uint32_t DIR_FileSize;
} __attribute__ ((packed)) DirEntry;

typedef struct {
	uint8_t LDIR_Ord;
	uint16_t LDIR_Name1[5];
	uint8_t LDIR_Attr;
	uint8_t LDIR_Type;
	uint8_t LDIR_Chksum;
	uint16_t LDIR_Name2[6];
	uint16_t LDIR_FstClusLO;
	uint16_t LDIR_Name3[2];
} __attribute__ ((packed)) LDirEntry;

typedef struct {
	uint32_t source; 			// Cluster donde se encuentran los (L)DirEntries del archivo/directorio
	uint32_t sourceOffset; 		// Sector del cluster donde se encuentran los (L)DirEntries (del 1 al 8)
	uint32_t content;			// Cluster donde comienza el contenido
	uint32_t nextCluster;		// LO + HI del DirEntry
	DirEntry shortEntry;		// LDirEntry del archivo/directorio
	LDirEntry longEntry;		// DirEntry del archivo/directorio
	uint32_t dirEntryOffset;	// size total de los (L)DirEntries ya leidos --> solo para directorios
	uint8_t	dirType;			// Define si es root o subdir: 0 = root ; 1 = subdir
	uint8_t flag;
} __attribute__ ((packed)) FatFile;

typedef struct {
uint16_t bps; 			// bytes per sector
uint16_t spc; 			// sectors per cluster
uint16_t bpc; 			// bytes per cluster
uint16_t fds; 			// first data sector
uint16_t rsv;			// reserved sector count

uint8_t	fatQty; 		// quantity of FAT tables
uint16_t fatSize; 		// size of FAT in sectors
uint16_t fatStartSector; // sector donde comienza la fat

uint32_t clusters;		// cluster quantity
uint32_t sectors;		// sector quantity
uint32_t dataSectors;	// data sector quantity
uint32_t root;			// cluster number of root directory

int32_t disk;			// disk file descriptor - solo ese usa en los tests
} __attribute__ ((packed)) Volume;

typedef struct {
	BPB boot;
	FSInfo infoSec;
	uint32_t cc_total; /*cantidad de total clusters*/
	uint32_t cs_reserved; /* Cantidad de sectores reservados reserved + (fatsize * cantfats)*/
	//lista sectores libres
	//TODO integrar funcion de listas para los sectores libres
	//arbol de directorios
	//TODO implementar arbol binario n-ario
} FatData;


#define LDIR_ISLAST(Ord)	((Ord & 0x40) == 0x40)
#define LFN_ISNULL(character)	(character == 0x00)

#define ATTR_READ_ONLY 0x1
#define ATTR_HIDDEN 0x2
#define ATTR_SYSTEM 0x4
#define ATTR_VOLUME_ID 0x8
#define ATTR_DIRECTORY 0x10
#define ATTR_ARCHIVE 0x20
#define ATTR_LONG_NAME ( ATTR_READ_ONLY | ATTR_HIDDEN | ATTR_SYSTEM | ATTR_VOLUME_ID )

#endif /* FAT_UTILS_H_ */
